package addCompo.imageBox
{
	
	import fl.core.InvalidationType;
	import fl.core.UIComponent;
	import fl.display.ProLoader;
	import fl.display.ProLoaderInfo;
	import fl.events.ComponentEvent;
	
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.HTTPStatusEvent;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLRequest;
	import flash.system.ApplicationDomain;
	import flash.system.LoaderContext;
	import flash.utils.ByteArray;	
	
	//--------------------------------------
	//  Events
	//--------------------------------------
	[Event("complete", type="flash.events.Event")]
	[Event("init", type="flash.events.Event")]
	[Event("ioError", type="flash.events.IOErrorEvent")]
	[Event("open", type="flash.events.Event")]
	[Event("progress", type="flash.events.ProgressEvent")]
	[Event("resize", type="fl.events.ComponentEvent")]
	[Event("securityError", type="flash.events.SecurityErrorEvent")]
	//--------------------------------------
	//  Styles
	//--------------------------------------
	//--------------------------------------
	//  Class description
	//--------------------------------------
	
	public class XMImageLoader extends UIComponent 
	{
		
		protected var _scaleContent:Boolean = true;
		
		protected var _autoLoad:Boolean = true;
		
		protected var contentInited:Boolean = false;
		
		protected var _source:Object; // Can be string, instance, class, etc.
		
		protected var loader:ProLoader;
		
		protected var _maintainAspectRatio:Boolean = true;
		
		protected var contentClip:Sprite;
		
		private static var defaultStyles:Object = {};
		
		public static function getStyleDefinition():Object { return defaultStyles; }
		
		public function XMImageLoader() 
		{
			super();
		}
		
		
		override public function setSize(w:Number, h:Number):void {
			if (!_scaleContent && _width > 0) { return; }
			super.setSize(w, h);
		}
		
		[Inspectable(defaultValue=true)]
		public function get autoLoad():Boolean {
			return _autoLoad;
		}
		public function set autoLoad(value:Boolean):void {
			_autoLoad = value;
			if (_autoLoad && loader == null && _source != null && _source != "") { load(); }
		}
		
		[Inspectable(defaultValue=true)]
		public function get scaleContent():Boolean {
			return _scaleContent;
		}
		public function set scaleContent(value:Boolean):void {
			if (_scaleContent == value) { return; }
			_scaleContent = value;
			invalidate(InvalidationType.SIZE);
		}
		
		[Inspectable(defaultValue=true)]
		public function get maintainAspectRatio():Boolean {
			return _maintainAspectRatio;
		}
		public function set maintainAspectRatio(value:Boolean):void {
			_maintainAspectRatio = value;			
			invalidate(InvalidationType.SIZE);
		}
		
		
		
		public function get bytesLoaded():uint {
			return (loader == null || loader.contentLoaderInfo == null) ? 0 : loader.contentLoaderInfo.bytesLoaded;
		}
		public function get bytesTotal():uint {
			return (loader == null || loader.contentLoaderInfo == null) ? 0 : loader.contentLoaderInfo.bytesTotal;
		}
		
		public function loadBytes(bytes:ByteArray, context:LoaderContext = null):void {
			_unload();
			initLoader();
			try {
				loader.loadBytes(bytes, context);
			} catch (error:*) {
				throw error;
			}
		}
		
		public function get content():DisplayObject {
			if (loader != null) {
				return loader.content;	
			} else if (contentClip.numChildren) {
				return contentClip.getChildAt(0);
			}
			return null;
		}
		
		[Inspectable(defaultValue="", type="String")]
		public function get source():Object {
			return _source;
		}
		public function set source(value:Object):void {
			if (value == "") { return; }
			_source = value;
			_unload();
			if (_autoLoad && _source != null) { 
				load();
			}
		}		
		
		public function get percentLoaded():Number {
			return (bytesTotal <= 0) ? 0 : bytesLoaded/bytesTotal*100;
		}
		
		public function load(request:URLRequest=null, context:LoaderContext = null):void {
			_unload();
			if ((request == null || request.url == null) && (_source == null || _source == "")) { return; }
			
			// Try and load the asset as a class/symbol/instance
			var asset:DisplayObject = getDisplayObjectInstance(source);
			if (asset != null) {
				contentClip.addChild(asset);
				contentInited = true;
				invalidate(InvalidationType.SIZE);
				return;
			}
			
			// Asset didn't load.  Try a URL Request
			var request:URLRequest = request;
			if (request == null) { // Request is null, so create it using the source.
				request = new URLRequest(_source.toString());
			}
			if (context == null) {
				context = new LoaderContext(false, ApplicationDomain.currentDomain);
			}
			
			initLoader();
			loader.load(request, context);
		}
		
		public function unload():void {
			_source = null;
			_unload(true);
		}
		
		public function close():void {
			try { 
				loader.close();
			} catch (error:*) {
				throw error;
			}
		}
		
		//--------------------------------------
		//  Protected methods
		//--------------------------------------
		
		protected function _unload(throwError:Boolean=false):void {
			if (loader != null) {
				clearLoadEvents();
				contentClip.removeChild(loader);
				try {
					loader.close();
				} catch (e:Error) {
					// Don't throw close errors.
				}
				
				try {
					loader.unload();
				} catch(e:*) {
					// Do nothing on internally generated close or unload errors.	
					if (throwError) { throw e; }
				}
				loader = null;
				return;
			}
			
			contentInited = false;
			if (contentClip.numChildren) {
				contentClip.removeChildAt(0);
			}			
		}
		
		protected function initLoader():void {
			loader = new ProLoader();
			loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR,handleError,false,0,true);
			loader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR,handleError,false,0,true);
			loader.contentLoaderInfo.addEventListener(Event.OPEN,passEvent,false,0,true);
			loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS,passEvent,false,0,true);
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE,handleComplete,false,0,true);
			loader.contentLoaderInfo.addEventListener(Event.INIT,handleInit,false,0,true);
			loader.contentLoaderInfo.addEventListener(HTTPStatusEvent.HTTP_STATUS,passEvent,false,0,true);
			contentClip.addChild(loader);	
		}
		
		protected function handleComplete(event:Event):void {
			clearLoadEvents();
			passEvent(event);
		}
		
		protected function passEvent(event:Event):void {
			dispatchEvent(event);
		}
		
		protected function handleError(event:Event):void {
			passEvent(event);
			clearLoadEvents();
			loader.contentLoaderInfo.removeEventListener(Event.INIT,handleInit);
		}
		
		protected function handleInit(event:Event):void {
			loader.contentLoaderInfo.removeEventListener(Event.INIT,handleInit);
			contentInited = true;
			passEvent(event);
			invalidate(InvalidationType.SIZE);
		}
		
		protected function clearLoadEvents():void {
			// clears all events except for INIT:
			loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR,handleError);
			loader.contentLoaderInfo.removeEventListener(SecurityErrorEvent.SECURITY_ERROR,handleError);
			loader.contentLoaderInfo.removeEventListener(Event.OPEN,passEvent);
			loader.contentLoaderInfo.removeEventListener(ProgressEvent.PROGRESS,passEvent);
			loader.contentLoaderInfo.removeEventListener(HTTPStatusEvent.HTTP_STATUS,passEvent);
			loader.contentLoaderInfo.removeEventListener(Event.COMPLETE,handleComplete);
		}
		
		override protected function draw():void {
			if (isInvalid(InvalidationType.SIZE)) {
				drawLayout();
			}
			super.draw();
		}
		
		protected function drawLayout():void {
			if (!contentInited) { return; }
			var resized:Boolean = false;
			
			var w:Number;
			var h:Number;			
			if (loader) {
				var cl:ProLoaderInfo = loader.contentLoaderInfo;
				w = cl.width;
				h = cl.height
			} else {
				w = contentClip.width;	
				h = contentClip.height;	
			}
			
			var newW:Number = _width;
			var newH:Number = _height;
			if (!_scaleContent) {
				_width = contentClip.width;
				_height = contentClip.height;
			} else {
				sizeContent(contentClip, w, h, _width, _height);
			}
			
			if (newW!= _width || newH != _height) {
				dispatchEvent(new ComponentEvent(ComponentEvent.RESIZE, true));
			}
		}
		
		protected function sizeContent(target:DisplayObject, contentWidth:Number, contentHeight:Number, targetWidth:Number, targetHeight:Number):void {
			var w:Number = targetWidth;
			var h:Number = targetHeight;
			if (_maintainAspectRatio) { // Find best fit. Center vertically or horizontally
				var containerRatio:Number = targetWidth / targetHeight;
				var imageRatio:Number = contentWidth / contentHeight;
				
				if (containerRatio < imageRatio) {
					h = w / imageRatio;
				} else {
					w = h * imageRatio;
				}
			}
			target.width = w;
			target.height = h;
			target.x = targetWidth/2 - w/2;
			target.y = targetHeight/2 - h/2;
		}
		
		override protected function configUI():void {
			super.configUI();
			contentClip = new Sprite();
			addChild(contentClip);
		}
	}
}
